home *** CD-ROM | disk | FTP | other *** search
- =======================================================
- Documentation for "The Killer Date Class!" Version 4.00
- =======================================================
-
- History
- =======
- In the beginning Steve Marcus (CIS 72007,1233) posted a basic date
- manipulation/arithmetic class produced with Borland C++ 2.0 in the
- BPROGB forum, with a request for suggestions and enhancements. This was
- on 6/19/91.
-
- A rather enterprising gentleman by the name of Eric Simon (CIS 70540,1522)
- accepted the challenge, and produced a new and improved version in the
- course of a project he was developing at work. He contributed the results
- to the forum on 6/29/91, also inviting enhancements and comments.
-
- About that time yet another enterprising gentleman named Christopher Hill
- developed a need for a universal date conversion routine for use in a
- business project he was developing as well. Browsing the same forum, he
- encountered Eric's class, which provided much of the functionality he needed
- - the basic julian-gregorian and day of week conversion algorithms -
- relieving him of the task of researching or re-inventing them. Eric had also
- added overloaded + and - operators for incrementing date objects by integer
- days, as well as several print functions. Chris needed additional features
- for his implementations, thus was born versions 3.0 and 3.1(Hill & Simon).
-
- Well, almost a year later I sent out an SOS for a date class so _I_ didn't
- have to re-invent the wheel and lo-and-behold Chris responded. Thus begins
- the saga of version 4.0! I would like to take this opportunity to do a
- little witnessing: I looked all over for a date class that would suit my
- needs! I reviewed many implementations from strangers and friends alike
- and I am here to tell ya' folks, "It don't 'git no bedder 'n dis!" This
- class is _VERY_ cool! Now I'm not trying to say that there's no more
- room for enhancements (I'd really be crazy then!), but I am saying that if
- your looking for a _GOOD_ date class (I'd say commercial quality because
- I have yet to see a commercial product that implemented a date class to
- my satisfaction!) then this is it! So jump in and add to it, make it
- better and we'll SAVE THE WORLD! (Ok, so I got a little carried away at
- the end. Just a little...)
-
- No, but really...
- This is a truly pleasing example of co-operation among professionals, and
- an "object" study in the code reusability of OOP, resulting in three releases
- of one class within a single month by three different analysts who have never
- met, and yet another upgrade almost a year later by a fourth analyst (myself)
- and none of us have yet to meet! Chris thanks Steve and Eric for their
- inspiration and generousity, and I thank all three as well and hereby
- contribute my additions to the public domain.
-
- I believe any of us would welcome further comments, suggestions and
- enhancements as well.
-
- Good luck! May the quest for the perfect date class continue!
-
- v4.9 Ly Minh Trí - 73062,512 01/26/94
- v4.8 Clyde Ford - 71426,72 11/18/93
- v4.7 Ly Minh Trí - 73062,512 09/20/93
- v4.6 Ly Minh Trí - 73062,512 08/04/93
- v4.5 Ly Minh Trí - 73062,512 06/21/93
- v4.4 Ly Minh Trí - 73062,512 06/03/93
- v4.3 Ly Minh Trí - 73062,512 03/24/93
- v4.2 Ly Minh Trí - 73062,512 03/13/93
- v4.1 Kenneth A. Argo - 71241,3635 03/07/93
- v4.0 Charles Price - 70541,3651 06/27/92
- v3.1 Hill & Simon - 08/05/91
- v3.0 Christopher Hill - 72030,2606 07/11/91
- v2.0 Eric Simon - 70540,1522 06/29/91
- v1.0 Steve Marcus - 72007,1233 06/16/91
-
- ===============================================================================
- TML - 01/26/94
-
- Version 4.9 fixes the Date::AddMonths() member function. The problem was it
- did not adjust the day value after the new month's value have been calculated.
- For example, if the current date is '08/31/1993' and 6 months is added to it
- using Date::AddMonths(), then the result is: 02/31/1994. Date::AddMonths()
- will now set the day value as appropriate for the new month. If the day value
- is greater than the # of days in that month, then it will roll the month over
- to the next month and set the day value to the difference between the day
- value and the # of days in the that month. Thanks to Patrick Cunningham this
- bug.
-
- This version also expands the Date::isDST() functionality by adding two new
- member functions: Date::setDST() and Date::setSTD(). Date::setDST() sets the
- month and day on which DST date begins. Likewise, Date::setSTD() sets the
- month and day on which STD date begins. Thanks to Marcelos Cantos for this
- suggestion.
-
- *********************** WARNING TO BORLAND C++ USERS *********************
-
- A couple of people have kindly informed me that the class Date is a pre-defined
- class in Borland C++. Thus, you will have to rename this class to another name
- like xDate, or DateCL or whatever is appropriate for your implementation!!!
-
- *******************************************************************************
-
- ===============================================================================
- TML - 11/18/93
-
- Version 4.8 adds a new member function Date::isDST() which was contributed by
- Clyde Ford (CIS 71426,72). Date::isDST() determines if the current date object
- is "within daylight savings time as defined in the United States". If so, then
- it will return 1, otherwise a 0 is returned.
-
- Please note that my CIS address has changed to 73062,512. If anyone have
- added new functions to DateClass and feel others may benefit from it, feel
- free to send me your code so I may incorporate it into future versions of
- DateClass. Or if you prefer, just incorporate the code, document your
- additions and upload it...
-
- ===============================================================================
-
- TML - 09/20/93
-
- Version 4.7 un-fixes the serious bug in the code for unary operators ++/--. In
- other words, they were originally correct. I guess I got really confused when
- I last talked to Jorge.
-
- Thanks to James M. Curran for informing me of this change. Also, James has a
- new version of DateClass (5.0) currently in the works. I think all of us will
- be very impress and receptive of his version!!!
-
- ===============================================================================
- TML - 08/04/93
-
- Version 4.6 fixes the Date::AddMonths() member function. It does not add or
- subtract the number of months correctly.
-
- Thanks to Patrick Cunningham for finding this bug!
-
- ===============================================================================
- TML - 06/21/93
-
- Version 4.5 fixes a very serious bug in the code for unary operators ++/--. I
- confused myself with the formats for prefix and postfix operations. (I got
- them reversed.) Jorge Padron was kind enough to inform me of my mistake.
-
- I also removed the 'const' keyword from parameter statements for functions which
- require variables to be passed by values (as opposed to pass by reference.) For
- example,
- Date operator + (const long i);
-
- is changed to:
-
- Date operator + (long i);
-
- I did it in the first place because I was trying to be consistent, but I realize
- that this can be confusing (especially those that are just learning C++). Jorge
- also pointed this out to me.
-
- ===============================================================================
- TML - 06/03/93
-
- Version 4.4 adds a little validation to the value of the day and month when an
- object is created via a string argument. For example, month must be from
- (1..12) and day must be from (1..n) where 'n' is the number of days for the
- given month.
-
- Thus, the following statements:
-
- Date myDate("02/31/1993");
- cout << myDate.formatDate() << "\n";
-
- will result in an "invalid date" output!
-
- ===============================================================================
-
- TML - 3/15/93
-
- Well, I must say, this is quite an impressive Date class!!! And I must
- agree with Mr. Kenneth...it's probably one of the BEST (if not the best) Date
- class I've seen so far (but then again, I've not seen too many!).
-
- However, I thought it really could take more advantage of some of the better
- features of C++ (ie. encapsulation!!!). Thus, I decided to take on the
- challenge set forth by the aforementioned 'Date'-crazed group.
-
- My changes are listed below in the Version 4.2 section. Please let me know
- of any updates/changes that will happen in the future!!!
-
- And ofcourse, we all welcome any comments/suggestions/participations!!!
-
- Ly Minh Trí :)
-
- ===============================================================================
-
- Implementation Notes
- ====================
-
- All versions prior to 4.0 were written specifically for a Borland C++
- compiler. However, version 4.0 was written specifically for
- Microsoft C++ 7.0. I too have attempted to optimize the code including
- the specification of const where applicable, the passing of references
- where advisable, and the use of constructor initializers where needed.
- However, I have not made an exhaustive analysis of this subject either.
-
- To get the best overview of the class capabilities run the demo program.
- It may not look pretty, but with a printout of a sample run and the code
- you should be able to get a really good feel for it. I have included a
- samples run at the end of this file in case someone doesn't want to
- take the time to compile the demo program.
-
- This ZIP file contains:
-
- MAKEFILE - make file to compile & link the files for MSC 7.0
- DATEDEMO.PRJ - project file for compiling under Borland C++ 3.1
- DATECL48.DOC - this file
- DATECL.H - the header file
- DATECL.CPP - the member functions
- DATEDEMO.CPP - a test program (and a messy one at that!)
- DATECL.LIB - a lib file so you can use it even if you
- don't have MSC7.0, or you just don't feel
- like fussin' with it! (Added in v4.0)
-
-
- Future possibilities for enhancement include
- ============================================
-
- 1. Adding a derived Time class, for those applications which require
- the ability to track more than just dates. This would allow the
- manipulation of times for all dates (not just since 1980), and
- arithmetic calculations as well.
-
- ===============================================================================
-
- Additions/Changes to Version 4.5
- ================================
-
- - Correct the implementation code for the unary operators ++ and --. These
- were reversed in version 4.2 to 4.3 (i.e. prefix was coded as postfix, and
- postfix was coded as prefix).
-
- - Removed 'const' keyword from parameter statments that requires variables to
- be passed by value.
-
- ===============================================================================
-
- Additions/Changes to Version 4.4
- ================================
-
- - Add a little validation to value of the day and month when an object is
- created via a string argument.
-
- ===============================================================================
-
- Additions/Changes to Version 4.3
- ================================
-
- - Add more flexibility in the constructor to support the many string formats
- that are used by the Date class.
-
- - Fix Date::Date(char *) and make it accept the string as a 'const' argument.
- Also, make a copy of the string ('dat') before passing it to strtok() since
- this function modifies its argument!
-
- - Remove the smaller buffer ('buf') and make use of only one buffer to save
- memory.
-
- - Re-code the type cast operator to call formatDate() so the current format
- and options will be applied to the resulting string.
-
- - Changed year to 'int' type to support B.C.E. dates.
-
- ===============================================================================
-
- Additions/Changes to Version 4.2
- ================================
-
- - Made it compatible to both Borland C++ (v 3.1) and Microsoft C++ (v 7.0)
- via #define switches. Define _BCC for Borland and _MSC for Microsoft.
- See the GO.BAT batch file!
-
- - Fix memory problems in Version 4.1. There were three 'deadly' memory
- threats introduced by Version 4.1:
-
- (a) In the destructor function, it is erroneous to delete buf without
- referring to it as a vector of characters. The proper method
- would be:
- delete [] buf; // Must have the brackets!
-
- Please review the section "The Free Store and Class Arrays" on
- page 95-99 of the _C++ Tutorial_ from Microsoft's C++ package!
-
- (b) In the Date::operator char *() function, variable buf was allocated
- space every time the function was called. This causes memory leaks
- when the same Date instance calls this operator function more than
- once during its lifetime.
-
- (c) Also in the Date::operator char *() function, variable buf was
- assigned the address of the constant string BadDate without prior
- release of the memory for buf.
-
- - Modified the following functions to return a Date object instead of a
- reference to a Date object!
-
- Date operator + (const long i);
- Date operator + (const int i);
- Date operator - (const long i);
- Date operator - (const int i);
- Date operator ++ ();
- Date operator ++ (int);
- Date operator -- ();
- Date operator -- (int);
-
- This is important because in Version 4.0 and before, the binary operators
- (+ and -) were declared to return references to Date objects since these
- functions dynamically creates a Date object when the function is called.
- However, there were no provisions for deleting these objects once they
- leave the scope of the function.
-
- In Version 4.1, Mr. Kenneth got rid of this problem of allocation by
- forcing the compiler to generate code to allocate stack space to return
- the objects. However, Mr. Kenneth 'forget?' to remove the references
- declaration. Why would this cause problem? Because when the calling
- program is expecting a reference in return (as opposed to a copy of the
- object), then that reference will be invalid since after the function
- terminates, the temporary object (used to return the value to the calling
- program) will also be terminated. Thus, the reference to the object is
- rendered obsolete.
-
- To test this, I wrote the following program:
-
-
- #include "datecls4.h"
- #include "iostream.h"
-
- void showDate(Date &dt)
- {
- cout << dt; // The (char *) type cast operator is in
- } // effect here!
-
- void main()
- {
- Date z("04/13/1967");
- showDate(z+3);
- }
-
- RESULT:
- *** destructor called *** // Temporary oject is destroyed
- 237/7/21
- *** destructor called *** // Object 'z' is destroyed
-
-
- As dictated by the result, the temporary object (created by the + operator)
- is destroyed before its values are displayed.
-
- By declaring the functions to return an actual Date object instead of a
- reference, we force the compiler to make a copy of it and return it to the
- calling program!
-
- - Fix implementation of the prefix/postfix operators to properly reflect the
- before/after syntax of the unary incrementor. (C++ provides only the
- the facility to determine which type of operator is being used, but the
- implementation is left to the programmer!)
-
- - Moved all buffer variables to the class level and made them private static
- member data.
- . for the Date::formatDate() function, the buffer is renamed to 'cbuf'
- . for the Date::Operator () function, the buffer is named 'buf'
-
- - Move all publically declared variables/enums into the public portion of
- the class. Also redefine the #define constants to an enum type. By doing
- this, we are taking advantage of C++'s encapsulation feature and reduce
- pollution of the global variable names. This concept is based on the ios
- class. (ie. ios::hex, ios::dec, etc.)
-
- - Also redeclare the 'friend' functions to be member functions (again, making
- use of encapsulation!)
-
- - Rewrote the Date::SetOption() function. (Made it more compact!)
-
- - Made use of the 'const' feature of C++ to ensure the references returned by
- most of the member functions will be non-modifiable by the calling program.
- (ie. force them to make a copy of it if they want to modify it!)
-
- - In the function Date::formatDate(), for the case Date::EUROPEAN and
- Date::EUROPEAN, fix the code (day_of_week < 0) to (day_of_week < 1). Also
- removed the statement strcat(cbuf, " ") and put the space into the
- sprintf() statement:
-
- sprintf( cbuf+strlen(cbuf), " %d", abs(year) );
-
- ===============================================================================
-
- Additions/Changes to Version 4.1
- ================================
-
- Fixed date display when using the * operator to get a string pointer.
- The code would return xx/xx/ xx if you only supplied a 2 digit year.
- Optimized the * operator so Invalid Dates would use a common "invalid date"
- text pointer.
- Fixed the +, - and * operators to get rid cases where memory leaks would
- occur.
- Fixed some variable casts so the code can be compiled with /W4
- Added a destructor tp delete items created dynamically on behalf of the
- object (ie. char *).
-
- Release Documentation for Version 4.0
- =====================================
- Most of the modifications made to version 3.1 were to expand the public
- interface. Below is a list of new features in v4.0:
-
- 1. Date &Set() - Sets self to current system date; this may also be
- accomplished by passing initializing a date object like so:
- Date oDate1("Today"); // See demo for examples
-
- 2. Date &Set(long lJulian) - Sets self to the specified julian date
-
- 3. Date &Set(int nMonth, int nDay, int nYear) - Sets self to specified
- month, day, and year. The year must be 4 numbers long, not 2.
-
- 4. Date &AddWeeks(int nCount = 1) - Add or subtract(use a negative int)
- a specified number of weeks to/from self
-
- 5. Date &AddMonths(int nCount = 1) - Add or subtract(use a negative int)
- a specified number of months to/from self
-
- 6. Date &AddYears(int nCount = 1); - Add or subtract(use a negative int)
- a specified number of years to/from self
-
- 7. int Day() const - Returns numeric day of the month for self
- 8. int DaysInMonth() - Returns number of days in month (1..31)
- 9. int FirstDOM() const - Returns the First Day Of Month for self as a
- numeric (1..7)
-
- 10. char *CDOW() - Returns character Day Of Week ('Sunday'..'Saturday')
- 11. int NDOW() const - Returns the numeric day of the week for self(1..7)
-
- 12. int WOM() - Returns numeric Week Of Month (1..6)
- 13. int WOY() - Returns numeric Week Of Year (1..52)
-
- 14. char *CMonth() - Character Month name ("January")
- 15. int NMonth() const - Month Number (1..12)
-
- 16. Date BOM() - Returns a new date object that is the First Date Of
- the Month in self. For example:
- Date oDate1;
- Date oDate2("Today");
- oDate1 = oDate2.BOM();
-
- 17. Date EOM() - Returns a new date object that is the Last Date Of
- the Month in self. (See example in 16 above)
-
- 18. int NYear4() const - Returns the numeric value of the year for self
- in the form 1992.
-
- 19. Date BOY() - Returns a new date object that is the First Date Of
- the Year in self. (See example 16 above)
-
- 20. Date EOY() - Returns a new date object that is the Last Date Of
- the Year in self. (See example 16 above)
-
- 21. Added overloaded operators for + and - to accept int's.
- 22. Added overloaded operators for ++ and -- for Postfix notation
-
- 23. Switched from the Borland style DOS date structure(date) to the
- Microsoft version(_dosdate_t).
-
- Suggestions and general comments are always welcome!
- Enjoy! Chuck :-}
-
-
-
- Release Documentation for Version 3.1
- =====================================
- Subsequent to release 3.00, we (Hill & Simon) decided to collaborate on
- several further releases of this date class. This, the first, contains two
- new features, as well as a few minor bug fixes.
-
- 1. There was a minor bug in the original Computer Language julian/gregorian
- date conversion routines having to do with negative years.
-
- 2. The isLeapYear function did not take into account that, prior to 1582,
- years ending in 00 were also leap years.
-
- 3. The two-dimensional array of the number of days in each month has been
- eliminated in favor of a computational approach.
-
- 4. The function Date::setFormat(XXXX) maintains a static variable (one
- occurance for all Date objects, which controls the format which the
- << operator uses to print objects. "XXXX" can be MONTH, MDY, DAY, FULL,
- or EUROPEAN. The setting defaults to MDY, but once altered, remains
- altered until reset by another call to setFormat.
-
- The function Date::setOption(Option, Action) maintains a similar static
- variable which enables certain print formatting options. Available options
- at this point are:
- NO_CENTURY -- Suppress the printing of the century when
- in the MDY format (ex: 01/01/91 instead of
- 01/01/1991).
-
- DATE_ABBR -- Abbreviate month and day names when printing
- in the MONTH, DAY, FULL or EUROPEAN formats.
- (ex. MON, TUE, JAN, FEB, etc.) The length
- or the abbreviation is controlled by a
- DEFINED constant in DATECL31.HPP named
- ABBR_LENGTH, preset to 3.
-
- "Action" is either ON or OFF, and defaults to ON. (Example, the call
- Date::setOption(NO_CENTURY) turns on the century suppression option, and
- it remains set until the call Date::setOption(NO_CENTURY, OFF) is made.
-
- More features, including further expanded print formatting features,
- the derived Time class mentioned above, conversion into various calendar
- formats (Jewish, Chinese, Arabic, etc.), ability to increment Date objects
- by years and months instead of merely days, holiday computations, and more
- are planned.
-
-
- Sample run of DATEDEMO.EXE v4.0
- ===============================
-
- Date Class v4.0 Demo
-
- Saturday, October 20, 1962
- Monday
- Tuesday, October 10, 1995
- Tuesday, October 30, 1962
- 5 October 1962
- -14
- 8/6/1991
- Tommorrow= Sunday, July 14, 1991
- a1 (7-14-91) < 8-01-91 ? ==> TRUE
- a1 (7-14-91) > 8-01-91 ? ==> FALSE
- a1 (7-14-91)== 7-14-91 ? ==> TRUE
- a1 (7-14-91)== a3 (7-14-91) ? ==> TRUE
- a1 (7-14-91)== a4 (7-15-91) ? ==> FALSE
- Today is: 6/28/1992
- Today (a4) is: 6/28/1992
- Today + 4 is: 7/2/1992
- Today - 4 is: 6/24/1992
- =========== Leap Year Test ===========
- Wednesday, January 15, 1992 Leap day of year: 15
- Tuesday, February 16, 1993 non-Leap day of year: 47
- =========== eom test ==============
- b1.eom() (s/b 2/28/91) ==> 2/28/1991
- ================== getDate test =====================
- a1.getDate() (s/b 2/16/1993) ==> 2/16/1993
- ================== string assignment test ====================
- a1 as a string (s/b 2/16/1993) ==> 2/16/1993
- ================== setFormat test ============================
- a1 (s/b FULL format) ==> Tuesday, February 16, 1993
- a1 (s/b EUROPEAN format) ==> 16 February 1993
- ================== setOption test ============================
- Date abbreviation ON
- a1 (s/b MONTH format) ==> Feb
- a1 (s/b DAY format) ==> Tue
- a1 (s/b FULL format) ==> Tue, Feb 16, 1993
- a1 (s/b EUROPEAN format) ==> 16 Feb 1993
- Century suppression ON
- a1 (s/b MDY format) ==> 2/16/93
- Century suppression OFF
- a1 (s/b MDY format) ==> 2/16/1993
- Century suppression ON
- a1 (s/b MDY format) ==> 2/16/93
- a1 (s/b FULL format) ==> Tue, Feb 16, 1993
-
- =============== Version 4.0 Enhancement Test =================
-
- ---------- Set Stuff -----------
- First, 'Set' to today...
- Before 'Set' => Saturday, November 26, 1966
- After 'Set' => Sunday, June 28, 1992
-
- Set to 11/26/66 => Saturday, November 26, 1966
- Current Julian => 2439455
- Set to Julian 2450000L => Tuesday, October 10, 1995
- See! => 2450000
- ---------- Add Stuff -----------
- Start => Tuesday, October 10, 1995
- Add 4 Weeks => Tuesday, November 7, 1995
- Sub 1 Month => Saturday, October 7, 1995
- Add 2 Years => Tuesday, October 7, 1997
- ---------- Misc Stuff -----------
- The date aboves' day of the month is => 7
- There are 31 days in this month.
- The first day of this month lands on 4
- This day happens to be Tuesday
- the 3 day of the week,
- on the 41 week of the year,
- on the 2 week of the month,
- (which is October)
- the 10nth month in the year.
- The year alone is 1997
- ---------- First and Last Stuff -----------
- The first date of this month is Monday, June 1, 1992
- The last date of this month is Tuesday, June 30, 1992
- The first date of this year is Wednesday, January 1, 1992
- The last date of this year is Thursday, December 31, 1992
-
-